﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Office.Tools.Ribbon;

namespace popoBCadd_in
{
    public partial class desain
    {
        //ATRIBUT
        private Microsoft.Office.Interop.Word.Document myDoc;
        private String user_key;

        //ATRIBUT FROM DESKTOP FORM
        byte[] message;
        long filesize;
        int chooseMode = 0;
        byte[] iv;
        byte[] resultmessage;
        

        //METHOD
        private void desain_Load(object sender, RibbonUIEventArgs e)
        {

        }

        #region encriptor decriptor
        /// <summary>
        /// main procedure for ENCRIPTING message
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void encript_Click(object sender, RibbonControlEventArgs e)
        {
            myDoc = Globals.ThisAddIn.GetActiveDocument();
            String a = myDoc.Content.Text;

            message = new byte[a.Length];
            for (int i = 0; i < a.Length; ++i)
            {
                message[i] = (byte)a[i];
            }

            //-----------------------------------
            chooseMode = 0;
            user_key = key.Text;
            filesize = message.Length;

            // init initial vector
            iv = new byte[user_key.Length + (user_key.Length % 2)];
            Random r = new Random();
            for (int i = 0; i < iv.Length; i++)
            {
                iv[i] = (byte)r.Next(255);
            }

            // create new message
            byte[] newmessage = new byte[filesize + iv.Length - (filesize % iv.Length)];


            //ADD some padding
            if (newmessage.Length != filesize)
            {
                //copy message to another container
                for (int i = 0; i < message.Length; ++i)
                {
                    newmessage[i] = message[i];
                }

                //add padding to newmessage
                for (int i = message.Length; i < newmessage.Length; ++i)
                {
                    newmessage[i] = 170;
                }
            }
            else
            {
                newmessage = message;
            }



            // START ENCRIPTION
            if (chooseMode == 0)  //ECB
            {
                newmessage = ECB.encrypt(newmessage,
                    generateTrueKey.getTrueKey(user_key));
            }
            else if (chooseMode == 1) //CBC
            {
                newmessage = CBC.encrypt(newmessage,
                    generateTrueKey.getTrueKey(user_key), iv);
            }
            else if (chooseMode == 2) //CFB
            {
                newmessage = CFB.encrypt(newmessage,
                    generateTrueKey.getTrueKey(user_key), iv);
            }
            else if (chooseMode == 3) //OFB
            {
                newmessage = OFB.encrypt(newmessage,
                    generateTrueKey.getTrueKey(user_key), iv);
            }


            //add someheader element
            byte[] header = getHeaderCipher();
            int headerlength = header.Length;
            resultmessage = new byte[newmessage.Length + headerlength];

            for (int i = 0; i < newmessage.Length; ++i)
            {
                resultmessage[i + headerlength] = newmessage[i];
            }

            for (int i = 0; i < headerlength; ++i)
            {
                resultmessage[i] = header[i];
            }

            resetAllVar();

            //-----------------------------------
            // FINAL RESULT --> REWRITE IN AREA
            String temp = "";
            for (int i = 0; i < resultmessage.Length; ++i)
                temp += (char)resultmessage[i];

            myDoc.Content.Text = temp;
        }



        /// <summary>
        /// main procedure for decripting message
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void decript_Click(object sender, RibbonControlEventArgs e)
        {
            if (key.Text != "")
            {
                myDoc = Globals.ThisAddIn.GetActiveDocument();
                String a = myDoc.Content.Text;

                message = new byte[a.Length];
                for (int i = 0; i < a.Length; ++i)
                {
                    message[i] = (byte)a[i];
                }


                // extract encription choosen Mode
                int chooseMode = extractEncriptionMode(message);

                // extract true file size without padding and header
                long truefilesize = extractFileSize(message);

                // extract initial vector saved in ciphertext
                byte[] iv = new byte[(key.Text.Length + key.Text.Length % 2)];
                iv = extractInitVector(message, iv.Length);

                int headersize = 1 + 8 + iv.Length;
                byte[] tempresultmessage = new byte[truefilesize + (iv.Length - (truefilesize % iv.Length))];
                int finalresultlength = tempresultmessage.Length;

                if (finalresultlength > (message.Length - headersize))
                {
                    finalresultlength = message.Length - headersize;
                }

                for (int i = 0; i < finalresultlength; ++i)
                {
                    tempresultmessage[i] = message[i + headersize];
                }


                //START DECRIPTION
                if (chooseMode == 0)  //ECB
                {
                    tempresultmessage = ECB.decrypt(tempresultmessage,
                        generateTrueKey.getTrueKey(key.Text));
                }
                else if (chooseMode == 1) //CBC
                {
                    tempresultmessage = CBC.decrypt(tempresultmessage,
                        generateTrueKey.getTrueKey(key.Text), iv);
                }
                else if (chooseMode == 2) //CFB
                {
                    tempresultmessage = CFB.decrypt(tempresultmessage,
                        generateTrueKey.getTrueKey(key.Text), iv);
                }
                else if (chooseMode == 3) //OFB
                {
                    tempresultmessage = OFB.decrypt(tempresultmessage,
                        generateTrueKey.getTrueKey(key.Text), iv);
                }


                // SAVE FINAL RESULT
                resultmessage = new byte[truefilesize];
                for (int i = 0; i < truefilesize; ++i)
                {
                    resultmessage[i] = tempresultmessage[i];
                }


                // SHOW FINAL RESULT
                String temp = "";
                for (int i = 0; i < resultmessage.Length; ++i)
                    temp += (char)resultmessage[i];

                myDoc.Content.Text = temp;


                resetAllVar();
            }
        }


        #endregion

        #region getter setter header
        //*******************************************************
        //MISCELANOUS FUNCTIONs
        //*******************************************************
        /// <summary>
        /// get header file info
        /// </summary>
        /// <returns></returns>
        private byte[] getHeaderCipher()
        {
            byte[] header = new byte[9 + iv.Length];

            for (int i = 0; i < 8; ++i)
            {
                header[i] = (byte)((filesize >> (7-i) * 8) & 255);
            }

            header[8] = (byte)chooseMode;

            for (int i = 0; i < iv.Length; ++i)
            {
                header[i + 9] = iv[i];
            }

            return header;
        }

        /*-----------------------------------------------
        /   EXTRACTOR HEADER FILE
        -----------------------------------------------*/
        private long extractFileSize(byte[] message)
        {
            long temp = 0;
            for (int i = 0; i < 8; ++i)
            {
                temp += message[i] << ((7 - i) * 8);
            }

            return temp;
        }

        private byte extractEncriptionMode(byte[] message)
        {
            return message[8];
        }

        private byte[] extractInitVector(byte[] message, int IVlength)
        {
            byte[] dummy = new byte[IVlength];

            for (int i = 0; i < IVlength; ++i)
            {
                dummy[i] = message[i + 9];
            }

            return dummy;
        }

        #endregion

        /// <summary>
        /// reset all variable in order to be used twice or more
        /// </summary>
        private void resetAllVar()
        {
            key.Text = "";
        }
    }
}
